/*
 *	This file is part of Lounge-Cast.
 *
 *  Author:  	Markus Moormann
 *	E-mail:  	mmoorman@uni-osnabrueck.de
 *	Copyright:	University of Osnabrueck (Zentrum Virtuos)
 * 	Website:	www.uni-osnabrueck.de
 *	Date:		16.02.2011
 *
 *	Lounge-Cast is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *	Lounge-Cast is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Lounge-Cast.  If not, see <http://www.gnu.org/licenses/>.
 */
package multimedia.control.command
{
	import com.adobe.cairngorm.commands.ICommand;
	import com.adobe.cairngorm.commands.SequenceCommand;
	import com.adobe.cairngorm.control.CairngormEvent;
	
	import flash.system.Capabilities;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.utils.getDefinitionByName;
	
	import multimedia.control.event.LoadVideoEvent;
	import multimedia.model.ModelLocator;
	import multimedia.model.vo.CaptionSetVO;
	import multimedia.model.vo.CaptionVO;
	import multimedia.model.vo.MediaElementVO;
	
	import org.osmf.buffering.DualThresholdBufferingProxyElement;
	import org.osmf.captioning.CaptioningPluginInfo;
	import org.osmf.captioning.model.Caption;
	import org.osmf.captioning.model.CaptionFormat;
	import org.osmf.captioning.model.CaptionStyle;
	import org.osmf.elements.DurationElement;
	import org.osmf.elements.ParallelElement;
	import org.osmf.elements.SerialElement;
	import org.osmf.elements.TextElement;
	import org.osmf.elements.VideoElement;
	import org.osmf.events.ContainerChangeEvent;
	import org.osmf.events.LoadEvent;
	import org.osmf.events.MediaElementEvent;
	import org.osmf.events.MediaFactoryEvent;
	import org.osmf.events.TimelineMetadataEvent;
	import org.osmf.layout.LayoutMetadata;
	import org.osmf.media.MediaElement;
	import org.osmf.media.MediaFactory;
	import org.osmf.media.MediaFactoryItem;
	import org.osmf.media.MediaResourceBase;
	import org.osmf.media.PluginInfoResource;
	import org.osmf.media.URLResource;
	import org.osmf.metadata.Metadata;
	import org.osmf.metadata.TimelineMetadata;
	import org.osmf.net.DynamicStreamingItem;
	import org.osmf.net.DynamicStreamingResource;
	import org.osmf.net.NetLoader;
	import org.osmf.net.StreamingURLResource;
	import org.osmf.traits.AudioTrait;
	import org.osmf.traits.LoadState;
	import org.osmf.traits.LoadTrait;
	import org.osmf.traits.MediaTraitType;
	import org.osmf.traits.PlayTrait;
	import org.osmf.traits.SeekTrait;


	/**
	 * 	LoadVideoCommand
	 *
	 *	@author jemden
	 *	@version 1.0
	 */
	public class LoadVideoCommand extends SequenceCommand implements ICommand
	{
		private var model:ModelLocator;

		private var e:LoadVideoEvent;

		private var video:MediaElement;

		private var media:MediaElement;

		private var captions:SerialElement;

		private var loadable:LoadTrait;
		
		private var captionMetadata:TimelineMetadata; 	
		private var savedCaptionText:String;
		private var mediaFactory:MediaFactory;
		private var videoLayout:LayoutMetadata
		
		override public function execute(event:CairngormEvent):void
		{
			this.model = ModelLocator.getInstance();
			this.e = LoadVideoEvent(event);
			this.nextEvent = e.nextEvent;
			
			model.log = "LoadVideoCommand " + e.video.url;
			
			var height:int = flash.system.Capabilities.screenResolutionY;
			var width:int = (e.video.aspect_ratio == "16:9" ? height * (16 / 9) : height * (4 / 3));

			//for resolution not 16/9
			//we need to start with the width
			if (width > flash.system.Capabilities.screenResolutionX)
			{
				width = flash.system.Capabilities.screenResolutionX;
				height = (e.video.aspect_ratio == "16:9" ? width / (16 / 9) : width / (4 / 3));
			}
			
			var resource:StreamingURLResource = new StreamingURLResource(e.video.url);
			resource.clipStartTime = e.video.inPoint;
			resource.clipEndTime = e.video.outPoint == 0 ? e.video.duration : e.video.outPoint;


			if (e.video.captionSets != null)
			{
				var metadata:Metadata = new Metadata();
				
				metadata.addValue(CaptioningPluginInfo.CAPTIONING_METADATA_KEY_URI, e.video.subtitles);
				resource.addMetadataValue(CaptioningPluginInfo.CAPTIONING_METADATA_NAMESPACE, metadata);
				
				var netLoader:NetLoader = new NetLoader();
				
				model.mediaFactory.addItem(new MediaFactoryItem("org.osmf.elements.video", netLoader.canHandleResource, 
					function createVideoElement():MediaElement
					{
						return new VideoElement();
					}));
				video = model.mediaFactory.createMediaElement(resource);
				
				videoLayout = new LayoutMetadata();
				video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout);
				videoLayout.x = Capabilities.screenResolutionX * 0.5 - width * 0.5;
				videoLayout.y = 0;
				videoLayout.height = height;
				videoLayout.width = width;
				
				captionMetadata = video.getMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE) as TimelineMetadata;
				if (captionMetadata == null)
				{
					captionMetadata = new TimelineMetadata(video);
					video.addMetadata(CaptioningPluginInfo.CAPTIONING_TEMPORAL_METADATA_NAMESPACE, captionMetadata);
				}
				captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_TIME_REACHED, onShowCaption);
				captionMetadata.addEventListener(TimelineMetadataEvent.MARKER_ADD, onHideCaption);
				media = video;
			} else 
			{
				// Create the new media
				video = new DualThresholdBufferingProxyElement(10, 30,
							new VideoElement(resource));
				videoLayout = new LayoutMetadata();
				video.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, videoLayout);
				videoLayout.x = Capabilities.screenResolutionX * 0.5 - width * 0.5;
				videoLayout.y = 0;
				videoLayout.height = height;
				videoLayout.width = width;
				media = video;
			}

			loadable = media.getTrait(MediaTraitType.LOAD) as LoadTrait;
			loadable.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadableStateChange);
			loadable.load();
		}

		private function onLoadableStateChange(event:LoadEvent):void
		{
			if (event.loadState == LoadState.READY)
			{
				trace("Video loaded");
				loadable.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadableStateChange);
				
				var audible:AudioTrait = video.getTrait(MediaTraitType.AUDIO) as AudioTrait;
				audible.volume = e.video.volume;
				
				if(e.video.inPoint != 0)
				{
					video.addEventListener(MediaElementEvent.TRAIT_ADD, 
						function traitAdd(event:MediaElementEvent):void
						{
							if(event.traitType == MediaTraitType.SEEK)
							{
								trace("seektrait finally added");
								var seek:SeekTrait = video.getTrait(MediaTraitType.SEEK) as SeekTrait;
								if(seek != null)
								{
									trace("can seek to:"+seek.canSeekTo(e.video.inPoint));
									seek.seek(e.video.inPoint);
								}
							}
						});
				}
				
				var play:PlayTrait = video.getTrait(MediaTraitType.PLAY) as PlayTrait;
				if(play != null)
				{
					trace("start playing shortly");
					play.play();
					play.pause();
				}
				
				model.mediaElements[(model.counter + 1)%4] = new MediaElementVO(e.video, media)
				
				executeNextCommand();
			}
		}
		
		private function onShowCaption(event:TimelineMetadataEvent):void
		{
			var caption:Caption = event.marker as Caption;
			
			// Make sure this is a caption object, and just for good measure, we'll
			// also check the namespace				
			if (model.captionEnabled && caption != null)
			{
				model.captionLabel.htmlText = caption.text;
				model.captionLabel.validateNow();
				formatCaption(caption);
			}
		}
		
		/**
		 * Handles formatting within the caption string.
		 */
		private function formatCaption(caption:Caption):void
		{
			for (var i:uint = 0; i < caption.numCaptionFormats; i++) 
			{
				var captionFormat:CaptionFormat = caption.getCaptionFormatAt(i);
				var txtFormat:TextFormat = new TextFormat();
				var style:CaptionStyle = captionFormat.style;
				
				if (style.textColor != null) 
				{
					txtFormat.color = style.textColor;
				}
				
				if (style.fontFamily != "") 
				{
					txtFormat.font = style.fontFamily;
				}
				
				if (style.fontSize > 0) 
				{
					txtFormat.size = style.fontSize;
				}
				
				if (style.fontStyle != "") 
				{
					txtFormat.italic = (style.fontStyle == "italic") ? true : false;
				}
				
				if (style.fontWeight != "") 
				{
					txtFormat.bold = (style.fontWeight == "bold") ? true : false;
				}
				
				if (style.textAlign != "") 
				{
					txtFormat.align = style.textAlign;
				}
				
				
				model.captionLabel.fieldText.setTextFormat(txtFormat, captionFormat.startIndex, 
					captionFormat.endIndex);
				if (model.captionLabel.wordWrap != style.wrapOption) 
				{
					model.captionLabel.wordWrap = style.wrapOption;
				}
			}				
		}
		private function onHideCaption(event:TimelineMetadataEvent):void
		{
			// Save the current caption text so we can easily re-display 
			// if user is toggling the captioning button
			savedCaptionText = model.captionLabel.htmlText;
			model.captionLabel.htmlText = "";
		}
	}
}